module tyrc_proc_path #(
	`include "tyrc_param.v")(	
    input                 clk,
    input                 rst_n,

    output [WORD_WD  -1:0]instruction,     //IR dec inst
    output                zero_flag,       //alu out to zero reg
    
    input                 load_r0,         //load bus2 to R0
    input                 load_r1,         //load bus2 to R1
    input                 load_r2,         //load bus2 to R2
    input                 load_r3,         //load bus2 to R3
    input                 load_pc,         //load bus2 to PC
    input                 load_ir,         //load bus2 to IR
    input                 load_reg_y,      //load bus2 to REG_Y
    input                 load_reg_z,      //load alu to REG_Z
    input                 load_add_r,      //load bus2 to ADDR_R
    input                 inc_pc,          //PC incr add
    input   [SEL1_WD -1:0]mux_sel_to_bus1, //src = R0/1/2/3/PC, to alu/bus2/mem
    input   [SEL2_WD -1:0]mux_sel_to_bus2, //src = alu/bus2/mem, to R0/1/2/3/PC/IR/REG_Y/ADD_R

	output  [ADDR_WD -1:0]addr			,//to mem, address
	output  [WORD_WD -1:0]bus1	 		,//to mem, data_in	
    input   [WORD_WD -1:0]mem_rdata
);

// ==========================================================================
// wire declare
// ==========================================================================
wire [WORD_WD -1:0]bus2;
wire [WORD_WD -1:0]com_r0;
wire [WORD_WD -1:0]com_r1;
wire [WORD_WD -1:0]com_r2;
wire [WORD_WD -1:0]com_r3;
wire [WORD_WD -1:0]pc;
wire [WORD_WD -1:0]reg_y;
wire [WORD_WD -1:0]alu_result;
wire [4       -1:0]inst_op;
wire [2       -1:0]inst_src;
wire [2       -1:0]inst_dst;
wire               alu_zero_flag;

assign {inst_op, inst_src, inst_dst} = instruction;

// ==========================================================================
// common reg
// ==========================================================================
tyrc_dffre #(.WD(WORD_WD))
u_com_r0(
    .clk(clk), 
    .rst_n(rst_n), 
    .d(bus2), 
    .en(load_r0), 
    .q(com_r0)
);

tyrc_dffre #(.WD(WORD_WD))
u_com_r1(
    .clk(clk), 
    .rst_n(rst_n), 
    .d(bus2), 
    .en(load_r1), 
    .q(com_r1)
);

tyrc_dffre #(.WD(WORD_WD))
u_com_r2(
    .clk(clk), 
    .rst_n(rst_n), 
    .d(bus2), 
    .en(load_r2), 
    .q(com_r2)
);

tyrc_dffre #(.WD(WORD_WD))
u_com_r3(
    .clk(clk), 
    .rst_n(rst_n), 
    .d(bus2), 
    .en(load_r3), 
    .q(com_r3)
);

// ==========================================================================
// pc & ir
// ==========================================================================
tyrc_program_count 
u_pc(
    .clk(clk),
    .rst_n(rst_n),
    .incr(inc_pc),
    .load(load_pc),
    .count_in(bus2),
    .count_out(pc)
);

tyrc_dffre #(.WD(WORD_WD))
u_ir(
    .clk(clk), 
    .rst_n(rst_n), 
    .d(bus2), 
    .en(load_ir), 
    .q(instruction)
);

// ==========================================================================
// mux and bus
// ==========================================================================
tyrc_bus1_mux
u_bus1(
    .sel(mux_sel_to_bus1),
    .in0(pc),
    .in1(com_r0),
    .in2(com_r1),
    .in3(com_r2),
    .in4(com_r3),
    .out(bus1)
);

tyrc_bus2_mux
u_bus2(
    .sel(mux_sel_to_bus2),
    .in0(mem_rdata),
    .in1(bus1),
    .in2(alu_result),
    .out(bus2)
);

// ==========================================================================
// alu
// ==========================================================================
tyrc_alu
u_alu(
    .in0(reg_y),
    .in1(bus1),
    .op(inst_op),
    .out(alu_result),
    .zero_flag(alu_zero_flag)
);

tyrc_dffre #(.WD(WORD_WD))
u_reg_y(
    .clk(clk), 
    .rst_n(rst_n), 
    .d(bus2), 
    .en(load_reg_y), 
    .q(reg_y)
);

tyrc_dffre #(.WD(1))
u_reg_z(
    .clk(clk), 
    .rst_n(rst_n), 
    .d(alu_zero_flag), 
    .en(load_reg_z), 
    .q(zero_flag)
);

tyrc_dffre #(.WD(WORD_WD))
u_add_r(
    .clk(clk), 
    .rst_n(rst_n), 
    .d(bus2), 
    .en(load_add_r), 
    .q(addr)
);

endmodule
